#include "EconomyAPI.h"
#include "EconomyPlugin.h"
#include "Managers/GameManager.h"
#include "Expand/PluginsManager.h"
#include "Subsystems/SubsystemPlayers.h"

#include "Expand/Plugins/AuthPlugin.h"

#include <fstream>
#include "spdlog/fmt/fmt.h"
#include "Network/Client.h"
#include "Player/PlayerData.h"

namespace Economy
{
    static const std::string titleText = "经济";

    constexpr const char *help1 = "\n"
                                  "/money    -查看自己现有的金钱\n"
                                  "/money help    -查看金钱有关的指令\n"
                                  "/money pay (玩家) (金额)    -向玩家支付金钱";

    constexpr const char *help2 = "\n"
                                  "/money    -查看自己现有的金钱\n"
                                  "/money help    -查看金钱有关的指令\n"
                                  "/money pay (玩家) (金额)    -向玩家支付金钱\n"
                                  "/money give (玩家) (金额)    -管理给玩家加金额\n"
                                  "/money dec (玩家) (金额)    -管理扣除玩家的金额\n"
                                  "/money set (玩家) (金额)    -管理设置玩家的金额\n"
                                  "/money get (玩家)    -管理查看玩家的金额\n"
                                  "/money giveguid (guid) (金额)    -管理给玩家加金额\n"
                                  "/money decguid (guid) (金额)    -管理扣除玩家的金额\n"
                                  "/money setguid (guid) (金额)    -管理设置玩家的金额\n"
                                  "/money getguid (guid)    -管理查看玩家的金额\n";

    static const std::string normalHelp = help1;
    static const std::string proHelp = help2;

    EconomyAPI::~EconomyAPI() {}

    void EconomyAPI::load()
    {
        m_subsystemPlayers = GameSingleton::singletonPtr->getSingleton<SubsystemPlayers>();

        m_authPlugin = GameSingleton::pluginsManager->findPlugin<AuthPlugin>();

        std::ifstream stream;
        stream.open(fmt::format("{}/EconomyAPI.json", EconomyPlugin::PluginDataDirectory));
        if (stream.is_open())
        {
            nlohmann::json jsonData;
            stream >> jsonData;
            Utils::GetJsonValue<uint32_t>(jsonData, m_defaultMoney, "defaultMoney", 0);
            Utils::GetJsonValue<std::map<GameGuid, uint32_t>>(jsonData, m_moneyMap, "data", std::map<GameGuid, uint32_t>());
        }
        else
        {
            m_defaultMoney = 0;
        }
        stream.close();
    }

    void EconomyAPI::save()
    {
        m_moneyMapMutex.lock();

        nlohmann::json jsonData = {
            {"defaultMoney", m_defaultMoney},
            {"data", m_moneyMap}};
        Utils::SaveTextFile(fmt::format("{}/EconomyAPI.json", EconomyPlugin::PluginDataDirectory), jsonData.dump());

        m_moneyMapMutex.unlock();
    }

    void EconomyAPI::sendHelpMessage(IPlugin::ChatObj &chatObj)
    {
        if (chatObj.m_isTerminal == true || m_authPlugin->getLevelByGuid(chatObj.m_client->guid) >= 100)
        {
            chatObj.sendMessage(titleText, proHelp);
        }
        else
        {
            chatObj.sendMessage(titleText, normalHelp);
        }
    }


    void EconomyAPI::sendGuidMessage(const GameGuid& gameGuid, const std::string &message)
    {
        PlayerDataPtr playerData = m_subsystemPlayers->getPlayerDataByGuid(gameGuid);
        if(playerData != nullptr)
        {
            IPlugin::ChatObj chatObj(playerData->client, false);
            chatObj.sendMessage(titleText, message);
        }
    }

    void EconomyAPI::sendPlayerMessage(PlayerDataPtr &playerDataPtr, const std::string &message)
    {
        // if (playerDataPtr != nullptr)
        {
            IPlugin::ChatObj chatObj(playerDataPtr->client, false);
            chatObj.sendMessage(titleText, message);
        }
    }


    void EconomyAPI::processCmd(IPlugin::ChatObj &chatObj, std::vector<std::string> &cmdDataVec)
    {
        if (cmdDataVec.size() == 1)
        {
            if (chatObj.m_isTerminal == true)
            {
                chatObj.sendMessage(titleText, "控制台不能使用该指令");
            }
            else
            {
                uint32_t money = getGuidMoney(chatObj.m_client->guid);
                chatObj.sendMessage(titleText, fmt::format("你现在有 {} $", money));
            }
            return;
        }
        else if (cmdDataVec.size() >= 4)
        {
            int32_t money = atoi(cmdDataVec[3].c_str());
            if (money > 0)
            {
                uint32_t authLevel = 0;
                if (chatObj.m_isTerminal == false)
                {
                    authLevel = m_authPlugin->getLevelByGuid(chatObj.m_client->guid);
                }

                //////////////////////////////////////////////////////////////////////////////////////////////////////
                // pay
                //////////////////////////////////////////////////////////////////////////////////////////////////////
                if (cmdDataVec[1] == "pay")
                {
                    if(chatObj.m_isTerminal == true)
                    {
                        chatObj.sendMessage(titleText, "控制台不能使用该指令");
                        return;
                    }
                    std::vector<PlayerDataPtr> playerVec;
                    m_subsystemPlayers->getPlayerDataByName(cmdDataVec[2], playerVec);
                    if (playerVec.size() > 1)
                    {
                        chatObj.sendMessage(titleText, "同名玩家超过2个，支付失败");
                    }
                    else if (playerVec.size() == 1)
                    {
                        GameGuid targetPlayerGuid = playerVec[0]->playerGuid;
                        uint32_t userMoney = getGuidMoney(chatObj.m_client->guid);
                        if(userMoney - money >= m_defaultMoney)
                        {
                            decGuidMoney(chatObj.m_client->guid, money);
                            addGuidMoney(targetPlayerGuid, money);
                            chatObj.sendMessage(titleText, fmt::format("你向 {} 支付了 {} $", cmdDataVec[2], money));
                            sendPlayerMessage(playerVec[0], fmt::format("玩家 {} 向你支付了 {} $", chatObj.m_client->nickname, money));

                            Log::Warn(fmt::format("玩家 {} 向 {} 支付了 {} $", chatObj.m_client->nickname, cmdDataVec[2], money));
                        }
                        else
                        {
                            chatObj.sendMessage(titleText, fmt::format("你支付金额后至少要保留 {} $", m_defaultMoney));
                        }
                    }
                    else
                    {
                        chatObj.sendMessage(titleText, fmt::format("玩家 {} 不在线", cmdDataVec[2]));
                    }
                    return;
                }
                else if (authLevel >= 100 || chatObj.m_isTerminal == true)
                {
                    //////////////////////////////////////////////////////////////////////////////////////////////////////
                    // give
                    //////////////////////////////////////////////////////////////////////////////////////////////////////
                    if (cmdDataVec[1] == "give")
                    {
                        std::vector<PlayerDataPtr> playerVec;
                        m_subsystemPlayers->getPlayerDataByName(cmdDataVec[2], playerVec);
                        if (playerVec.size() > 1)
                        {
                            chatObj.sendMessage(titleText, "同名玩家超过2个");
                        }
                        else if (playerVec.size() == 1)
                        {
                            GameGuid targetPlayerGuid = playerVec[0]->playerGuid;
                            addGuidMoney(targetPlayerGuid, money);
                            chatObj.sendMessage(titleText, fmt::format("你给了 {} 金钱 {} $", cmdDataVec[2], money));
                            sendPlayerMessage(playerVec[0], fmt::format("你从管理员那里获得了金钱 {} $", money));
                            if(chatObj.m_isTerminal == false)
                            {
                                Log::Warn(fmt::format("管理员 {} 给了 {} 金钱 {} $", chatObj.m_client->nickname, cmdDataVec[2], money));
                            }
                        }
                        else
                        {
                            chatObj.sendMessage(titleText, fmt::format("玩家 {} 不在线", cmdDataVec[2]));
                        }
                        return;
                    }
                    //////////////////////////////////////////////////////////////////////////////////////////////////////
                    // give
                    //////////////////////////////////////////////////////////////////////////////////////////////////////
                    else if (cmdDataVec[1] == "dec")
                    {
                        std::vector<PlayerDataPtr> playerVec;
                        m_subsystemPlayers->getPlayerDataByName(cmdDataVec[2], playerVec);
                        if (playerVec.size() > 1)
                        {
                            chatObj.sendMessage(titleText, "同名玩家超过2个");
                        }
                        else if (playerVec.size() == 1)
                        {
                            GameGuid targetPlayerGuid = playerVec[0]->playerGuid;
                            decGuidMoney(targetPlayerGuid, money);
                            chatObj.sendMessage(titleText, fmt::format("你扣除 {} 金钱 {} $", cmdDataVec[2], money));
                            sendPlayerMessage(playerVec[0], fmt::format("你被管理员扣除了金钱 {} $", money));
                            if(chatObj.m_isTerminal == false)
                            {
                                Log::Warn(fmt::format("管理员 {} 扣除了 {} 金钱 {} $", chatObj.m_client->nickname, cmdDataVec[2], money));
                            }
                        }
                        else
                        {
                            chatObj.sendMessage(titleText, fmt::format("玩家 {} 不在线", cmdDataVec[2]));
                        }
                        return;
                    }
                    //////////////////////////////////////////////////////////////////////////////////////////////////////
                    // give
                    //////////////////////////////////////////////////////////////////////////////////////////////////////
                    else if (cmdDataVec[1] == "set")
                    {
                        std::vector<PlayerDataPtr> playerVec;
                        m_subsystemPlayers->getPlayerDataByName(cmdDataVec[2], playerVec);
                        if (playerVec.size() > 1)
                        {
                            chatObj.sendMessage(titleText, "同名玩家超过2个");
                        }
                        else if (playerVec.size() == 1)
                        {
                            GameGuid targetPlayerGuid = playerVec[0]->playerGuid;
                            setGuidMoney(targetPlayerGuid, money);
                            chatObj.sendMessage(titleText, fmt::format("你将 {} 的金钱设置成 {} $", cmdDataVec[2], money));
                            sendPlayerMessage(playerVec[0], fmt::format("你的金钱被管理员设置成 {} $", money));
                            if(chatObj.m_isTerminal == false)
                            {
                                Log::Warn(fmt::format("管理员 {} 将 {} 的金钱设置成 {} $", chatObj.m_client->nickname, cmdDataVec[2], money));
                            }
                        }
                        else
                        {
                            chatObj.sendMessage(titleText, fmt::format("玩家 {} 不在线", cmdDataVec[2]));
                        }
                        return;
                    }
                    //////////////////////////////////////////////////////////////////////////////////////////////////////
                    // giveguid
                    //////////////////////////////////////////////////////////////////////////////////////////////////////
                    else if (cmdDataVec[1] == "giveguid")
                    {
                        GameGuid playerGuid(cmdDataVec[2]);
                        std::string playerName;
                        if (m_subsystemPlayers->playerGuidGetName(playerGuid, playerName))
                        {
                            addGuidMoney(playerGuid, money);
                            chatObj.sendMessage(titleText, fmt::format("你给了 {} 金钱 {} $", playerName, money));
                            sendGuidMessage(playerGuid, fmt::format("你从管理员那里获得了金钱 {} $", money));
                            if(chatObj.m_isTerminal == false)
                            {
                                Log::Warn(fmt::format("管理员 {} 给了 {} 金钱 {} $", chatObj.m_client->nickname, playerName, money));
                            }
                        }
                        else
                        {
                            chatObj.sendMessage(titleText, fmt::format("不存在 guid 为 {} 的玩家", cmdDataVec[2]));
                        }
                        return;
                    }
                    //////////////////////////////////////////////////////////////////////////////////////////////////////
                    // decguid
                    //////////////////////////////////////////////////////////////////////////////////////////////////////
                    else if (cmdDataVec[1] == "decguid")
                    {
                        GameGuid playerGuid(cmdDataVec[2]);
                        std::string playerName;
                        if (m_subsystemPlayers->playerGuidGetName(playerGuid, playerName))
                        {
                            decGuidMoney(playerGuid, money);
                            chatObj.sendMessage(titleText, fmt::format("你扣除 {} 金钱 {} $", playerName, money));
                            sendGuidMessage(playerGuid, fmt::format("你被管理员扣除了金钱 {} $", money));
                            if(chatObj.m_isTerminal == false)
                            {
                                Log::Warn(fmt::format("管理员 {} 扣除了 {} 金钱 {} $", chatObj.m_client->nickname, playerName, money));
                            }
                        }
                        else
                        {
                            chatObj.sendMessage(titleText, fmt::format("不存在 guid 为 {} 的玩家", cmdDataVec[2]));
                        }
                        return;
                    }
                    //////////////////////////////////////////////////////////////////////////////////////////////////////
                    // setguid
                    //////////////////////////////////////////////////////////////////////////////////////////////////////
                    else if (cmdDataVec[1] == "setguid")
                    {
                        GameGuid playerGuid(cmdDataVec[2]);
                        std::string playerName;
                        if (m_subsystemPlayers->playerGuidGetName(playerGuid, playerName))
                        {
                            setGuidMoney(playerGuid, money);
                            chatObj.sendMessage(titleText, fmt::format("你将 {} 的金钱设置成 {} $", playerName, money));
                            sendGuidMessage(playerGuid, fmt::format("你的金钱被管理员设置成 {} $", money));
                            if(chatObj.m_isTerminal == false)
                            {
                                Log::Warn(fmt::format("管理员 {} 将 {} 的金钱设置成 {} $", chatObj.m_client->nickname, playerName, money));
                            }
                        }
                        else
                        {
                            chatObj.sendMessage(titleText, fmt::format("不存在 guid 为 {} 的玩家", cmdDataVec[2]));
                        }
                        return;
                    }
                }
            }
            else
            {
                chatObj.sendMessage(titleText, "乱搞可是会被封号的！！！");
                return;
            }
        }
        else if (cmdDataVec.size() == 3)
        {
            if (cmdDataVec[1] == "get")
            {
                std::vector<PlayerDataPtr> playerVec;
                m_subsystemPlayers->getPlayerDataByName(cmdDataVec[2], playerVec);
                if (playerVec.size() > 1)
                {
                    chatObj.sendMessage(titleText, "同名玩家超过2个");
                }
                else if (playerVec.size() == 1)
                {
                    GameGuid targetPlayerGuid = playerVec[0]->playerGuid;
                    uint32_t money = getGuidMoney(targetPlayerGuid);
                    chatObj.sendMessage(titleText, fmt::format("玩家 {} 现在有 {} $", cmdDataVec[2], money));
                }
                else
                {
                    chatObj.sendMessage(titleText, fmt::format("玩家 {} 不在线", cmdDataVec[2]));
                }
                return;
            }
            else if (cmdDataVec[1] == "getguid")
            {
                GameGuid playerGuid(cmdDataVec[2]);
                std::string playerName;
                if (m_subsystemPlayers->playerGuidGetName(playerGuid, playerName))
                {
                    uint32_t money = getGuidMoney(playerGuid);
                    chatObj.sendMessage(titleText, fmt::format("玩家 {} 现在有 {} $", playerName, money));
                }
                else
                {
                    chatObj.sendMessage(titleText, fmt::format("不存在 guid 为 {} 的玩家", cmdDataVec[2]));
                }
                return;
            }
        }
        sendHelpMessage(chatObj);
    }

    void EconomyAPI::setGuidMoney(const GameGuid &guid, uint32_t money)
    {
        m_moneyMapMutex.lock();

        auto it = m_moneyMap.find(guid);
        if (it != m_moneyMap.end())
        {
            it->second = money;
        }
        else
        {
            m_moneyMap[guid] = money;
        }

        m_moneyMapMutex.unlock();
    }

    uint32_t EconomyAPI::getGuidMoney(const GameGuid &guid)
    {
        std::lock_guard<std::mutex> lk(m_moneyMapMutex);

        auto it = m_moneyMap.find(guid);
        if (it != m_moneyMap.end())
        {
            return it->second;
        }
        else
        {
            m_moneyMap[guid] = m_defaultMoney;
        }
        return m_defaultMoney;
    }

    void EconomyAPI::addGuidMoney(const GameGuid &guid, uint32_t money)
    {
        m_moneyMapMutex.lock();

        auto it = m_moneyMap.find(guid);
        if (it != m_moneyMap.end())
        {
            it->second += money;
        }
        else
        {
            m_moneyMap[guid] = m_defaultMoney + money;
        }

        m_moneyMapMutex.unlock();
    }

    void EconomyAPI::decGuidMoney(const GameGuid &guid, uint32_t money)
    {
        m_moneyMapMutex.lock();

        auto it = m_moneyMap.find(guid);
        if (it != m_moneyMap.end())
        {
            if (it->second > money)
            {
                it->second -= money;
            }
            else
            {
                it->second = 0;
            }
        }
        else
        {
            if (m_defaultMoney > money)
            {
                m_moneyMap[guid] = m_defaultMoney - money;
            }
            else
            {
                m_moneyMap[guid] = 0;
            }
        }

        m_moneyMapMutex.unlock();
    }

}
